package UDPTools;

import Messages.Exceptions.MessageCreationException;
import Network.Exceptions.NetworkException;
import UDPTools.Settings.UDPSettings;
import UDPTools.Interface.UDPListenerInterface;
import Network.Interface.NetworkListenerInterface;
import UDPTools.Exceptions.UDPListernerException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;
import messages.Message;
import messages.MessagesFactory;

/**
 * La classe UDPListener prend en charge la reception des messages distants
 * Elle reçoit tous les signaux de l'utilisateur distants et les remonte au ChatNetwork. 
 * UDPListener implemente deux interfaces:
 * <ul>
 * <li>Runnable              Pour lancer le thread de reception des signaux
 * <li>UDPListenerInterface  Pour activer et desactiver l'ecoute du réseau.
 * </ul>
 * 
 * @author      Frank Djomo
 * @author      Christelle SIAGO HAPPI
 * @author      djomopoueme@gmail.com
 * @author      christelle.siagohappi@gmail.com
 * @version     1.0
 * @see     UDPListenerInterface
 */

public class UDPListener implements Runnable,UDPListenerInterface{

    private DatagramSocket socket;
    private NetworkListenerInterface ni;
    private  boolean bListening;
    private int portEcoute;

    /**
     * Contructeur
     * @param  ni objet de type NetworkListenerInterface 
     */
    public UDPListener(NetworkListenerInterface ni) {
            this(ni,UDPSettings.UDP_PORT_ECOUTE);
    }
    /**
     * Contructeur
     * @param  ni    Ojet de type NetworkListenerInterface
     * @param  local Port d'ecoute
     */
    public UDPListener(NetworkListenerInterface ni,int local){
        this.ni=ni;
        this.portEcoute=local;
        this.bListening = true;
    }
    /**
     * La methode <code>StartListening</code> gère le démarrage de l'écoute sur la socket
     * @throws UDPListernerException 
     */
    @Override
    public void StartListening() throws UDPListernerException {

        boolean  bSucceded = false;
        while(!bSucceded)
        {
            try {
                socket = new DatagramSocket(portEcoute);
                bSucceded = true;
                (new Thread(this)).start();
            } 
            catch (SocketException se) 
            {
                throw new UDPListernerException("Echec creation de la socket ",se);
            }
        }
    }  
    /**
    * La methode <code>StopListening</code> gère l'arrêt de l'écoute sur la socket
    */
    @Override
    public synchronized void StopListening() {
        bListening = false;
    }
    
    /**
     * La methode <code>run</code> est exécuté par le thread du UDPListener
     */
    @Override
    public void run() {

        while(bListening) {

                byte[] streamByte = new byte[1500];
                DatagramPacket inPacket = new DatagramPacket(streamByte, streamByte.length);
                try {
                    socket.receive(inPacket);
                    Message recvMessage = MessagesFactory.getMessage(inPacket.getData());
                	System.out.println("UDPListener("+portEcoute+") a recu un message");

                    if(recvMessage != null)
                       this.ni.receivedMessage(recvMessage,inPacket.getAddress());
                } 
            catch (NetworkException ex) {
                Logger.getLogger(UDPListener.class.getName()).log(Level.SEVERE, null, ex);
            }            catch (MessageCreationException ex) {
                Logger.getLogger(UDPListener.class.getName()).log(Level.SEVERE, null, ex);
            }            catch (IOException ex) {
                Logger.getLogger(UDPListener.class.getName()).log(Level.SEVERE, null, ex);
            }                
        }
    }

}
